/**
	Provides simple iteration for arrays, objects, xml nodes, and anything implementing the IterableInterface.

	@author Chandler McWilliams
	@version 2005-11-11
	@see IterableInterface
	
	@usage
		<code>
		var looper = new Iterator(myData);
		while((item=looper.next()) !== false) {
			trace(looper.getCurrentKey() + ' = ' + item);
		}
		</code>

*/
class timber.collection.Iterator
{
	
	private var collection;
	private var index;
	private var length;
	private var keys; // used when wrapping an object
	private var type;

// ===========================================================
// - CONSTRUCTOR
// ===========================================================
	public function Iterator(aCollection) {
		collection = aCollection;
		index = -1;
		
		// change for type
		switch (true) {
			case (collection.isIterable && collection.isIterable()):
				type = 'iterable'
				length = collection.getLength();
				break;

			case (collection instanceof Array):
				type = 'array';
				length = collection.length;
				break;
						
			case (collection instanceof XML):
				type = 'xml';
				length = collection.firstChild.childNodes.length;
				break;

			default:
				type = 'object';
				// save keys
				keys = [];
				for (var i in collection) keys.push(i);
				length = keys.length;				
				break;
		}
	}

// ===========================================================
// - ACCESSORS
// ===========================================================
	public function getType() {
		return type;
	}

	public function getLength() {
		return length;
	}

// ===========================================================
// - ITERATION METHODS
// ===========================================================
	public function next() {
		setCurrentIndex(getNextIndex());
		if (index === false) return false;
		return getItemAtIndex(index);
	}
	
	public function current() {
		return getItemAtIndex(index);
	}
	
	public function prev() {
		setCurrentIndex(getPrevIndex());
		if (index === false) return false;
		return getItemAtIndex(index);
	}

// ===========================================================
// - INDEX METHODS
// ===========================================================
	public function rewind() { setCurrentIndex(-1); }
	
	/** Alias for rewind. 	*/
	public function reset() { rewind(); }
	public function setCurrentIndex(val) { index = val; }
	public function getCurrentIndex() {	return index; }
	public function getNextIndex() {
		return (index+1 >= length)?false:index+1;
	}	
	
	public function getPrevIndex() {
		return (index-1 < 0)?false:index-1;
	}

// ===========================================================
// - KEY METHODS
// ===========================================================
	public function key() { return getCurrentKey(); }
	public function getCurrentKey() {
		if (isObject()) return keys[getCurrentIndex()];
		return index;
	}

	public function getNextKey() {
		if (isObject()) return keys[getNextIndex()];
		return getNextIndex();
	}	
	
	public function getPrevKey() {
		if (isObject()) return keys[getPrevIndex()];
		return getPrevIndex();
	}
		


// ===========================================================
// - ITEM ACCESS
// ===========================================================
	public function getItemAtIndex(i) {
		
		// switch for type
		switch(true) {
			case isIterable():
				return collection.getItemAtIndex(i);

			case isArray():
				return collection[i];
			
			case isObject():
				return collection[keys[i]];

			case isXML():
				return collection.firstChild.childNodes[i];
		}
	}
	
	public function getNextItem() {
		var i = getNextIndex();
		if (i===false) return false;
		return getItemAtIndex(i);
	}	

	public function getPrevItem() {
		var i = getPrevIndex();
		if (i===false) return false;
		return getItemAtIndex(i);
	}
	

// ===========================================================
// - TYPE METHODS
// ===========================================================
	public function isIterable() {
		return (type == 'iterable');
	}

	public function isObject() {
		return (type == 'object');
	}

	public function isArray() {
		return (type == 'array');
	}

	public function isXML() {
		return (type == 'xml');
	}
}